<template>
  <my-dialog
    v-model="showDialog"
    :show-mark="false"
    :mark-close="false"
    :icon-close="!isLoading"
    :width="345"
  >
    <div class="dynamic-edit">
      <textarea
        ref="wordInpRef"
        class="dynamic-edit__word"
        rows="4"
        maxlength="1800"
        placeholder="记录这一美好时刻吧"
        @keyup.ctrl.enter.prevent="startSend"
      />
      <div class="disabled-word" v-if="isLoading"></div>
      <div
        :class="{
          'dynamic-edit__img': true,
          'dynamic-edit__img--one': imgs.length < 4,
          'dynamic-edit__img--two': imgs.length > 4 && imgs.length < 7,
          'dynamic-edit__img--three': imgs.length > 7,
        }"
      >
        <img
          draggable="false"
          v-for="(item, index) in imgs"
          :key="item"
          class="img-item"
          :src="item"
          alt=""
          @click="imgClick(index)"
          @mousedown="mousedown(index, $event)"
        />
        <img-upload ref="uploadRef" @change="change">
          <i
            class="img-item upload-img flex"
            :class="{ 'upload-img__disabled': isLoading || imgs.length === 9 }"
            @click="handleToUpload"
          >
            <SvgIcon icon-class="camera" style="color: #cdd0d6" /></i
        ></img-upload>
      </div>
      <toolbar
        :textarea-ele="($refs.wordInpRef as any)"
        @update-content="updateContent"
        :disabled="isLoading"
        @change="change"
      ></toolbar>
    </div>
    <div class="dynamic-setup">
      <ul>
        <li class="clearfix" @click="toPickPermission">
          <span
            ><SvgIcon
              icon-class="people"
              popper-class="dynamic-setup__icon"
            />动态权限</span
          >
          <span style="float: right"
            >{{ pickValue.tag }}
            {{ pickValue.childrenType ? `(${pickValue.childrenType})` : ""
            }}<SvgIcon icon-class="rightArrow" style="margin-left: 10px"
          /></span>
          <pick-permission
            v-model="showPermission"
            :mouse-coord="mouseCoord"
            :pick-value="pickValue"
            :user-id="user.userId"
          ></pick-permission>
        </li>
      </ul>
    </div>
    <transition name="fade"
      ><div ref="imgDeleRef" class="img-delete" v-show="showDeleteButton">
        <i class="flex img-delete__icon"
          ><SvgIcon v-show="isEnterDele" icon-class="deleteOpen" /><SvgIcon
            v-show="!isEnterDele"
            icon-class="deleteClose"
        /></i></div
    ></transition>
    <template #footer>
      <el-button
        :disabled="isLoading"
        type="primary"
        @click="startSend"
        :loading="isLoading"
        style="width: 100%"
        title="按住Ctrl+Enter发表"
        ><template #loading><Loading /></template>发表</el-button
      >
    </template>
  </my-dialog>
  <img-browse
    v-model="showImgBrowse"
    v-model:img-index="imgIndex"
    :imgs="imgs"
  ></img-browse>
</template>

<script lang="ts" setup>
import { ref, watch, reactive } from "vue";
import myDialog from "@/components/ui-components/dialog.vue";
import imgUpload from "./imgUpload.vue";
import { ElMessage } from "element-plus";
import imgBrowse from "@/components/ui-components/imgBrowse.vue";
import toolbar from "./toolbar.vue";
import pickPermission from "./pickPermission.vue";
import { useDynamicPinia } from "@/pinia/dynamic";
import { useUserPinia } from "@/pinia/user";
import { storeToRefs } from "pinia";

const props = defineProps<{
  modelValue: boolean;
}>();

const emits = defineEmits<{
  (e: "update:modelValue", show: boolean): void;
}>();

const dynamicStore = useDynamicPinia();
const { user } = storeToRefs(useUserPinia());

/**
 * 给文字编辑输入框一个ref属性
 */
const wordInpRef = ref<any>();
/**
 * 是否打开对话框
 */
const showDialog = ref<boolean>(false);

watch(
  () => props.modelValue,
  (show: boolean) => {
    showDialog.value = show;
    if (show) setTimeout(() => wordInpRef.value.focus(), 0);
    else {
      setTimeout(() => {
        imgs.splice(0);
        pickValue.value.tag = "全部";
        pickValue.value.type = 0;
        pickValue.value.childrenType = "";
        pickValue.value.children.size && pickValue.value.children.clear();
      }, 310);
    }
  }
);

watch(
  () => showDialog.value,
  (show: boolean) => emits("update:modelValue", show)
);

/**
 * 用户即将发表的图片集合
 */
const imgs = reactive<string[]>([]);
// 当用户上传图片后收集该图片url
const change = (urls: string[]) =>
  imgs.length + urls.length > 9
    ? ElMessage({
        type: "warning",
        message: "抱歉，最多只能上传9张图片",
        duration: 1500,
      })
    : imgs.push(...urls);

// 给imgrUpload组件一个ref属性
const uploadRef = ref<InstanceType<typeof imgUpload>>();
/**
 * 是否正在发送动态
 */
const isLoading = ref<boolean>(false);

// 上传图片
const handleToUpload: () => void = (): void => {
  if (!isLoading.value)
    imgs.length === 9
      ? ElMessage({
          type: "warning",
          message: "抱歉，最多只能上传9张图片",
          duration: 1500,
        })
      : (uploadRef.value as any).uploadImg();
};

/**
 * 是否显示图片浏览组件
 */
const showImgBrowse = ref<boolean>(false);
/**
 * 当前用户所浏览的图片的索引值
 */
const imgIndex = ref<number>(0);
// 点击图片进行浏览
const imgClick = (index: number) => {
  showImgBrowse.value = true;
  imgIndex.value = index;
};

/**
 * 是否显示删除图片按钮
 */
const showDeleteButton = ref<boolean>(false);
/**
 * 用户点击图片后是否松开鼠标
 */
const isUp = ref<boolean>(false);
/**
 * 给图片删除框一个ref属性
 */
const imgDeleRef = ref<HTMLDivElement>(document.createElement("div"));
/**
 * 图片是否进入到删除区域
 */
const isEnterDele = ref<boolean>(false);

// 当点击图片时
const mousedown = (index: number, $event: MouseEvent) => {
  if (isLoading.value) return;
  isUp.value = false;
  imgIndex.value = index;
  const imgEle = $event.target as HTMLImageElement;
  const newImg = new Image();
  newImg.draggable = false;
  newImg.width = imgEle.width;
  newImg.height = imgEle.height;
  newImg.src = imgEle.src;
  newImg.style.cssText +=
    "position: absolute; z-index: 2001; opacity: 0.7; object-fit: cover;";
  const rect = imgEle.getBoundingClientRect();
  newImg.style.cssText += `top: ${rect.y}px; left: ${rect.x}px`;
  // 此时鼠标点击处距离浏览器左边界的距离
  const startX: number = $event.clientX;
  // 此时鼠标点击处距离浏览器上边界的距离
  const startY: number = $event.clientY;
  // 拖拽元素距离浏览器上边界的距离
  const imgTop: number = rect.y + scrollY;
  // 拖拽元素距离浏览器左边界的距离
  const imgLeft: number = rect.x + scrollX;
  // 视图可视宽度
  let bodyWid: number = document.body.scrollWidth;
  // 如果出现滚动条此时可能设置了body的padding-right来防止页面抖动
  const bodyPaddRight: number = +document.body.style.paddingRight.replace("px", "");
  if (bodyPaddRight) bodyWid -= bodyPaddRight;
  // 视图可视高度
  const bodyHei: number = document.body.scrollHeight;
  // 鼠标在水平方向最多可移动的距离
  const maxX: number = bodyWid - imgEle.width - imgLeft;
  // 鼠标在竖直方向最多可移动的距离
  const maxY: number = bodyHei - imgEle.height - imgTop;

  document.onmousemove = (e: MouseEvent) => {
    if (!isUp.value) {
      if (!showDeleteButton.value) showDeleteButton.value = true;
      setTimeout(() => {
        !document.body.contains(newImg) && document.body.append(newImg);
        // 鼠标水平移动的距离
        let left: number = e.clientX - startX;
        // 鼠标竖直移动的距离
        let top: number = e.clientY - startY;

        // 边界处理
        if (left > maxX) left = maxX;
        else if (-left > imgLeft) left = -imgLeft;

        if (top > maxY) top = maxY;
        else if (-top > imgTop) top = -imgTop;

        newImg.style.cssText += `top: ${imgTop + top}px; left: ${imgLeft + left}px`;

        const deleIconEle: HTMLElement = imgDeleRef.value.getElementsByClassName(
          "img-delete__icon"
        )[0] as HTMLElement;
        const newImgTop: number = +newImg.style.top.replace("px", "");
        const newImgLeft: number = +newImg.style.left.replace("px", "");

        const imgDeleRect = imgDeleRef.value.getBoundingClientRect();
        const deleX = imgDeleRect.x;
        const deleY = imgDeleRect.y;

        if (
          ((deleY - newImgTop > 0 && deleY - newImgTop < newImg.height) ||
            (deleY - newImgTop < 0 &&
              newImgTop - deleY < imgDeleRef.value.offsetHeight)) &&
          ((deleX - newImgLeft > 0 && deleX - newImgLeft < newImg.width) ||
            (deleX - newImgLeft < 0 && newImgLeft - deleX < imgDeleRef.value.offsetWidth))
        ) {
          deleIconEle.style.cssText += "background-color: rgb(255, 0, 102);color: #fff";
          isEnterDele.value = true;
        } else {
          deleIconEle.style.cssText = "";
          isEnterDele.value = false;
        }
      });
    }
  };

  document.onmouseup = () => {
    isUp.value = true;
    document.onmousemove ? (document.onmousemove = null) : undefined;
    document.onmouseup = null;
    if (showDeleteButton.value) showDeleteButton.value = false;
    setTimeout(() => {
      document.body.contains(newImg) && document.body.removeChild(newImg);
      if (isEnterDele.value) {
        imgs.splice(imgIndex.value, 1);
        isEnterDele.value = false;
      }
    }, 10);
  };
};

/**
 * 该用户选择的谁能看该条动态
 */
const pickValue = ref<{
  tag: "全部" | "私密" | "部分可看" | "谁不能看";
  type: 0 | 1 | 2 | 3;
  childrenType: "分组" | "朋友" | "";
  children: Set<string>;
}>({
  tag: "全部",
  type: 0,
  childrenType: "",
  children: new Set(),
});
/**
 * 是否显示选择动态权限组件
 */
const showPermission = ref<boolean>(false);
/**
 * 鼠标点击的坐标
 */
const mouseCoord = ref<{ x: number; y: number }>({ x: 0, y: 0 });
// 选择动态权限
const toPickPermission = (e: MouseEvent) => {
  if (!isLoading.value) {
    mouseCoord.value.x = e.clientX;
    mouseCoord.value.y = e.clientY;
    showPermission.value = true;
  }
};

// 是否更新编辑的内容(往往是执行了插入表情操作)
const updateContent = (payload: { isModify: boolean; content?: string }) =>
  payload.isModify ? (wordInpRef.value.value = payload.content) : undefined;

// 开始发送动态
const startSend = () => {
  const content: string = wordInpRef.value.value.trim();
  if (!content.length && !imgs.length) {
    ElMessage({
      type: "warning",
      message: "编辑的内容不能为空",
      duration: 1500,
    });
    wordInpRef.value.focus();
  } else {
    wordInpRef.value.blur();
    isLoading.value = true;
    dynamicStore
      .sendDynamic({
        selfId: user.value.userId,
        content,
        imgs: [...imgs],
        permission: {
          tagType: pickValue.value.type,
          childrenType: pickValue.value.childrenType === "分组" ? 0 : 1,
          children: [...pickValue.value.children],
        },
      })
      .then((code: number) => {
        isLoading.value = false;
        if (code === 1) {
          emits("update:modelValue", false);
          ElMessage({
            type: "success",
            message: "发表成功",
            duration: 1500,
          });
        } else {
          wordInpRef.value.focus();
          ElMessage({ type: "error", message: "发表失败", duration: 1500 });
        }
      })
      .catch(() => {
        isLoading.value = false;
        ElMessage({ type: "error", message: "发表失败", duration: 1500 });
        wordInpRef.value.focus();
      });
  }
};
</script>

<style lang="scss" scoped>
.fade {
  @include fade(0.4s, ease);
}

.img-delete {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: rgba(0, 0, 0, 0.2);
  padding: 6px 0;

  &__icon {
    margin: 0 auto;
    @include setWidHei(40px, 40px);
    background-color: #fff;
    border-radius: 50%;
    font-size: 20px;
    transition: background-color 0.25s;
  }
}

.dynamic {
  &-edit {
    position: relative;
    margin-top: -8px;

    .disabled {
      &-word {
        position: absolute;
        top: 0;
        background-color: rgba(255, 255, 255, 0.619);
        @include setWidHei(300px, 80px);
        z-index: 10;
        cursor: not-allowed;
      }
    }

    &__word {
      border: 0;
      outline: none;
      @include setWidHei(100%, 76px);
      resize: none;
      font-size: 16px;
      @include scrollBar;

      &::placeholder {
        font-size: 14px;
      }
    }

    &__img {
      margin-top: 8px;
      display: grid;
      grid-template-columns: 70px 70px 70px 70px;
      grid-row-gap: 5px;
      grid-column-gap: 5px;

      &--one {
        grid-template-rows: 70px;
      }

      &--two {
        grid-template-rows: 70px 70px;
      }

      &--three {
        grid-template-rows: 70px 70px 70px;
      }

      .img-item {
        @include setWidHei(70px, 70px);
        cursor: pointer;
        object-fit: cover;
      }

      .upload-img {
        font-size: 30px;
        background-color: #fafafa;
        border: 1px dashed #e4e6eb;
        transition: border-color 0.35s;

        &:hover {
          border-color: #c3ccdf;
        }

        &__disabled {
          cursor: not-allowed;
        }
      }
    }
  }

  &-setup {
    margin-top: 9px;

    li {
      position: relative;
      padding: 6px 0;
      cursor: pointer;

      & > span {
        transition: color 0.25s;
      }

      &:hover > span {
        color: #79bbff;
      }
    }

    &__icon {
      margin-right: 10px;
      font-size: 16px;
    }
  }
}
</style>
